{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import numpy.linalg as npl\n",
    "import math\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7.1 Geometric Transformations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.5      , -0.8660254],\n",
       "       [ 0.8660254,  0.5      ]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#a rotation matrix:\n",
    "Rotation = lambda angle:np.array([[np.cos(angle), -np.sin(angle)],[np.sin(angle),np.cos(angle)]])\n",
    "r60 = Rotation(np.pi/3)\n",
    "r60"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.5       , 0.8660254 ],\n",
       "       [0.75      , 1.29903811],\n",
       "       [1.        , 1.73205081],\n",
       "       [0.28349365, 0.9910254 ],\n",
       "       [0.53349365, 1.42403811],\n",
       "       [0.0669873 , 1.1160254 ]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#some list of 2d points:\n",
    "pts = np.array([[1,0],[1.5,0],[2,0],[1,.25],[1.5,.25],[1,.5]])\n",
    "r60pts = np.vstack([np.matmul(r60,p) for p in pts])\n",
    "r60pts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x11a4325f8>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter([pts[i][0] for i in range(len(pts))],[pts[i][1] for i in range(len(pts))])\n",
    "plt.scatter([r60pts[i][0] for i in range(len(pts))],[r60pts[i][1] for i in range(len(pts))])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "#a reflection matrix\n",
    "Reflection = lambda angle:np.array([[np.cos(2*angle),np.sin(2*angle)],[np.sin(2*angle),-np.cos(2*angle)]])\n",
    "reflect60 = Reflection(np.pi/3)\n",
    "ref60pts = np.vstack([np.matmul(reflect60,p) for p in pts])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x11a517898>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter([pts[i][0] for i in range(len(pts))],[pts[i][1] for i in range(len(pts))])\n",
    "plt.scatter([ref60pts[i][0] for i in range(len(pts))],[ref60pts[i][1] for i in range(len(pts))])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7.2 Selectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., 0., 1.],\n",
       "       [0., 0., 0., 1., 0.],\n",
       "       [0., 0., 1., 0., 0.],\n",
       "       [0., 1., 0., 0., 0.],\n",
       "       [1., 0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "flipper = lambda n: np.flip(np.eye(5),1) #J: reverse(eye(n), dims=1)\n",
    "A = flipper(5)\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1., 2., 3., 4., 5.]), array([5., 4., 3., 2., 1.]))"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#reverse order of x with reverser (flipper) matrix\n",
    "x = np.array([1.,2.,3.,4.,5.])\n",
    "x, np.matmul(A,x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5., 4., 3., 2., 1.])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#can also just flip x directly:\n",
    "np.flip(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(matrix([[0, 0, 1],\n",
       "         [1, 0, 0],\n",
       "         [0, 1, 0]]), array([ 0.2, -1.7,  2.4]))"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A,x = np.matrix([[0,0,1],[1,0,0],[0,1,0]]), np.array([.2,-1.7,2.4])\n",
    "A,x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[ 2.4,  0.2, -1.7]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(A,x) #permutations of x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 2.4,  0.2, -1.7])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[[2,0,1]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7.3 Incidence Matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Flow in an incidence matrix\n",
    "A = np.matrix([[-1,-1,0,1,0],[1,0,-1,0,0],[0,0,1,-1,-1],[0,1,0,0,1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[0, 0, 0, 0]])"
      ]
     },
     "execution_count": 126,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "xcirc = np.array([1,-1,1,0,1])\n",
    "np.matmul(A,xcirc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 127,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = np.array([1,0,-1,0])\n",
    "x = np.array([.6,.3,.6,-.1,-.3])\n",
    "np.matmul(A,x)+s "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[-1, -1,  0,  1,  0],\n",
       "        [ 1,  0, -1,  0,  0],\n",
       "        [ 0,  0,  1, -1, -1],\n",
       "        [ 0,  1,  0,  0,  1]])"
      ]
     },
     "execution_count": 128,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Dirichlet energy is a measure of how variable a function is\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 2, 1])"
      ]
     },
     "execution_count": 153,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vsmooth = np.array([1,2,2,1])\n",
    "vsmooth"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3, -4])"
      ]
     },
     "execution_count": 158,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Reminder on matrix vector mult:\n",
    "A = np.array([[0,2,-1],[-2,1,1]])\n",
    "x = np.array([2,1,-1])\n",
    "np.matmul(A,x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 198,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.9999999999999996"
      ]
     },
     "execution_count": 198,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[-1,-1,0,1,0],[1,0,-1,0,0],[0,0,1,-1,-1],[0,1,0,0,1]]).transpose()\n",
    "#Note: A needs to be transposed because Julia automatically \n",
    "#calculates column wise based on dimension of vsmooth and A\n",
    "vsmooth = np.array([1,2,2,1])\n",
    "npl.norm(np.matmul(A,vsmooth))**2 #J: norm(A'*vsmooth)^2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 199,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27.0"
      ]
     },
     "execution_count": 199,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vrough = np.array([1,-1,2,-1])\n",
    "npl.norm(np.matmul(A,vrough))**2 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7.4 Convolution"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Convolution is applying one function to another and getting a third function that describes how the application of the second function affected the initial function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 2,  3, -3, -1,  1, -2])"
      ]
     },
     "execution_count": 200,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a,b,c = np.array([1,1]),np.array([2,-1,1]),np.array([1,1,-2])\n",
    "d = np.convolve(np.convolve(a,b),c)\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 320,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1.,  0.,  0.,  0.],\n",
       "       [ 2., -1.,  0.,  0.],\n",
       "       [ 3.,  2., -1.,  0.],\n",
       "       [ 0.,  3.,  2., -1.],\n",
       "       [ 0.,  0.,  3.,  2.],\n",
       "       [ 0.,  0.,  0.,  3.]])"
      ]
     },
     "execution_count": 320,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#a matrix can be convolved into toeplitz form \n",
    "#by holding diagonals constant\n",
    "def toeplitz(b,n):\n",
    "    m = len(b)\n",
    "    T = np.zeros((n+m-1,n))\n",
    "    for i in range(m):\n",
    "        for j in range(len(T[i])):\n",
    "            T[j+i][j]=b[i]\n",
    "            #J: T[i:n+m:end] .= b[i]\n",
    "            #there probably exists a more elegant implementation\n",
    "    return T\n",
    "b,a = np.array([-1,2,3]), np.array([-2,3,-1,1])\n",
    "Tb = toeplitz(b,len(a))\n",
    "Tb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 323,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ 2., -7.,  1.,  6., -1.,  3.]), array([ 2, -7,  1,  6, -1,  3]))"
      ]
     },
     "execution_count": 323,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(Tb,a), np.convolve(b,a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 330,
   "metadata": {},
   "outputs": [],
   "source": [
    "m,n = 2000,2000\n",
    "b,a = np.random.randn(n), np.random.randn(m)\n",
    "toep = toeplitz(b,n)*a\n",
    "conv = np.convolve(a,b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 327,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.62 s ± 94.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit toep = toeplitz(b,n)*a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 328,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "558 µs ± 35.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit conv = np.convolve(a,b)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
